console.log("cavas-table");
import theme from "./theme"

const TABLE_BODY = 4;

function getOrDefault(v, defaultV) {
  return v === undefined ? defaultV : v;
}
function isFunction(f) {
  return typeof f === "function";
}
function isObject(o) {
  return o !== null && typeof o === "object";
}

function drawTextInGrid(ctx, text, x, y, w, h, style) {
  const {fontSize, color, align, borderColor, borderWidth} = style;
  ctx.save();
  ctx.rect(x, y, w, h);
  ctx.clip();
  if (style.backgroundColor) {
      ctx.fillStyle = style.backgroundColor;
      ctx.fillRect(x, y, w, h);
  }
  ctx.font = `${fontSize}px monospace`;
  ctx.fillStyle = color || theme.COLOR;
  let xOffset = x;
  const yOffset = y + h - (h-fontSize) / 2;
  const textWidth = ctx.measureText(text).width;
  if (align === 'left') {
      xOffset = x;
  } else if (align === 'right') {
      xOffset = x + (w - textWidth);
  } else { // default: center
      xOffset = x + (w - textWidth)/2;
  }
  ctx.fillText(text, xOffset, yOffset);
  ctx.strokeStyle = borderColor;
  ctx.lineWidth = borderWidth;
  ctx.beginPath();
  ctx.moveTo(x, y+h);
  ctx.lineTo(x+w, y+h);
  ctx.closePath();
  ctx.stroke();
  ctx.restore();
}

function getCell(x, y, cols, rows, option) {
  let rowIndex = 0, colIndex = null, width = 0, row = null, col = null;
  rowIndex = Math.floor(y / option.rowHeight);
  for(let i=0; i<cols.length; i++) {
      width += cols[i].width_c;
      if (width >= x) {
          colIndex = i;
          break;
      }
  }
  if (rows && rows.length > 0 && rows[rowIndex] !== undefined) {
      row = rows[rowIndex];
  }
  if (colIndex !== null) {
      col = cols[colIndex];
  }
  return {row, col}
}


export class CanvasTable {
  constructor(rootElm) {
    // 不做太多初始化，仅创建canvas元素
    this.rootElm = rootElm;
    this.canvas = document.createElement("canvas");
    this.ctx = this.canvas.getContext("2d");
    rootElm.appendChild(this.canvas);
    this.bindEvent();
  }

  init(option) {
    if (!option || typeof option !== "object") {
      throw `CanvasTable: option Invalid: ${option}`;
    }
    // if (!(option.cols instanceof Array)) {
    //   throw `CanvasTable: option.cols Invalid: ${option.cols}`;
    // }
    // if (!(option.list instanceof Array)) {
    //   throw `CanvasTable: option.list Invalid: ${option.list}`;
    // }

    this.option = option;

    this.initOption(option);

    window.requestAnimationFrame(this.draw.bind(this));
  }
  // 这里有问题，需要改进，分两种转换，一种是 设计尺寸到canvas像素， 一种是css像素到canvas像素
  design_to_canvas_px(x) {
    if (x === undefined || x === null) return x;
    return x ;
  }
  canvas_to_css_px(x) {
    if (x === undefined || x === null) return x;
    return x / this.pixelRatio;
  }
  css_to_canvas_px(x) {
    if (x === undefined || x === null) return x;
    return x * this.pixelRatio;
  }
  initOption(option) {
    const { designWidth, top, left } = option;
    const { ctx } = this;
    // pixelRatio: 像素比例，canvas像素比css像素的值，就是1个css像素对应几个canvas像素
    // designScale: canvas宽度与设计稿宽度的比例，不指定设计稿宽度则为1，此值用来计算实际绘制尺寸，比如线宽、文字大小等。 drawValue = valueSpecified * designScale;
    this.pixelRatio = window.devicePixelRatio;
    const boundingRect = this.rootElm.getBoundingClientRect();
    this.cssWidth = boundingRect.width;
    this.canvasWidth = boundingRect.width * this.pixelRatio;
    this.designWidth = designWidth || boundingRect.width * this.pixelRatio;
    if (this.canvasWidth < this.designWidth) {
      this.canvasWidth = this.designWidth;
      this.pixelRatio = this.canvasWidth / boundingRect.width;
    }
    this.designScale = this.canvasWidth / this.designWidth; // 在不指定designWidth的情况下，为1，值域大于等于1

    this.fillDefaultOption(option);

    let cssHeight = Math.max(boundingRect.height, option.maxHeight);
    // const tableCssHeight = Math.ceil(
    //   (option.list.length * option.rowHeight +
    //     option.headHeight +
    //     option.scrollbarWidth) /
    //     this.pixelRatio
    // );
    // cssHeight = Math.min(cssHeight, tableCssHeight);
    this.canvasHeight = cssHeight;

    this.cssHeight = cssHeight;
    this.canvas.style.display = "block";

    // viewWidth, viewHeight 主canvas可视区的宽高，排除滚动条的

    const tableContentWidth = option.normalCols.reduce((acc, i) => {
      return acc + getOrDefault(i.width_c, option.colWidth);
    }, 0);
    const tableContentHeight = option.list.length * option.rowHeight;

    const tableWidth = tableContentWidth;
    const tableHeight = tableContentHeight;

    this.tableWidth = tableWidth;
    this.tableHeight = tableHeight;

    this.canvas.width = this.tableWidth;
    this.canvas.height = this.tableHeight;
    this.viewWidth = this.canvasWidth;
    this.viewHeight = this.canvasHeight;

    console.log(option);
  }

  fillDefaultOption(option) {
    const initValue = (v, dv) => {
      if (v === undefined || v === null) {
        return this.design_to_canvas_px(dv);
      } else {
        return this.design_to_canvas_px(v);
      }
    };

    option.color = getOrDefault(option.color, theme.COLOR);
    option.backgroundColor = getOrDefault(option.backgroundColor, theme.BACKGROUND_COLOR);
    option.borderColor = getOrDefault(option.borderColor, theme.BORDER_COLOR);
    option.borderWidth = initValue(option.borderWidth, 1);
    option.rowHeight = initValue(option.rowHeight, 40);
    option.colWidth = initValue(option.colWidth, 150);
    option.fontSize = initValue(option.fontSize, 28);
    option.maxHeight = getOrDefault(option.maxHeight, 0); // css value
    option.normalCols = [];
    option.cols.forEach((col) => {
      col.align = getOrDefault(col.align, "center");
      col.titleAlign = getOrDefault(col.titleAlign, col.align);
      col.sort = getOrDefault(col.sort, false);
      col.fixed = getOrDefault(col.fixed, false);
      col.width_c = this.design_to_canvas_px(col.width) || option.colWidth; // 每列的canvas像素宽度
      option.normalCols.push(col);
    });
  }

  draw() {
    console.log('ccccccccc')
    const ctx = this.ctx;
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    console.log("🚀 ~ file: index.js:174 ~ CanvasTable ~ draw ~ ctx.canvas.width, ctx.canvas.height:", ctx.canvas.width, ctx.canvas.height)
    ctx.save();
    this.renderSubView();
    ctx.restore();
  }

  renderSubView() {
    let rect;
    const { normalCols, fixedCols } = this.option;
    const { tableWidth, tableHeight } = this;
    rect = { x: 0, y: 0, w: tableWidth, h: tableHeight };
    this.renderBody(rect, normalCols, TABLE_BODY);
  }

  // render content
  renderBody(rect, cols, canvasId) {
    console.log(rect)
    const {list, colWidth, color, rowHeight, borderColor, borderWidth} = this.option;
    const { ctx } = this;
    let x = 0, y = 0;
    ctx.save();
    ctx.rect(rect.x, rect.y, rect.w, rect.h);
    // ctx.clip();
    
    const bodyTop = this.top;
    const bodyBottom = this.top + this.tableHeight;
    list.forEach(row => {
      x = 0;
      if (y + rowHeight < bodyTop || y > bodyBottom) {
          y += rowHeight;
          return;
      }
      cols.forEach(col => {
          var fontSize = this.option.fontSize;
          let textColor = color;
          const width = col.width_c;
          let text;
          if (isFunction(col.draw)) {
              const ok = col.draw(row, ctx, new Rect(x, y, width, rowHeight));
              if (!ok) { this.waitingRender = true; }
          } else {
              if (isFunction(col.formatter)) {
                  text = col.formatter(row);
              } else {
                  text = row[col.field]
              }
              if (isObject(text)) {
                  const o = text;
                  text = o.text;
                  textColor = o.color || textColor;
                  fontSize = o.fontSize || fontSize;
              }
              console.log('xxxxx')
              drawTextInGrid(ctx, text, x, y, width, rowHeight, {
                  fontSize,
                  color: textColor,
                  align: col.align,
                  borderColor,
                  borderWidth,
                  backgroundColor: row.backgroundColor,
              });
          }
          x += width;
      });
      y += rowHeight;
  });
  ctx.restore();


  }

  bindEvent(){
    this.canvas.addEventListener('click', this.clickHandler.bind(this));
  }

  clickHandler(e) {
    const x = e.clientX, y = e.clientY;
    var rect = this.canvas.getBoundingClientRect()
    const cx = Math.floor(x - rect.left);
    const cy = Math.floor(y - rect.top);
    const {option} = this;
    const {normalCols,  list} = option;

    let cell=null
    cell = getCell(cx, cy, normalCols, list, option);
    if (cell.col) {
      this.clickCell({...cell});
  }

  }
  clickCell(cell) {
    if (isFunction(this.onclick)) {
        this.onclick(cell);
    }
}
}
